package br.edu.infnet.business;

import br.edu.infnet.dto.ClienteDTO;
import br.edu.infnet.dto.ContaDTO;
import br.edu.infnet.dto.MovimentoDTO;
import br.edu.infnet.exception.BankException;
import br.edu.infnet.infraestrutura.AuthCodeGenerator;
import br.edu.infnet.infraestrutura.Operacao;
import br.edu.infnet.infraestrutura.TipoConta;
import br.edu.infnet.model.Cliente;
import br.edu.infnet.model.Conta;
import br.edu.infnet.model.Movimento;
import br.edu.infnet.repositorio.RepositorioCliente;
import br.edu.infnet.repositorio.RepositorioConta;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;

/**
 * Session Bean implementation class ServicoClienteBean
 */
@Stateless
@Local(IServicoCliente.class)
@LocalBean
public class ServicoClienteBean implements IServicoCliente {

	@EJB
	RepositorioConta contarepo;
	@EJB
	RepositorioCliente clienterepo;
    /**
     * Default constructor. 
     */
    public ServicoClienteBean() {
    	//contarepo = new RepositorioConta();
        //clienterepo = new RepositorioCliente();
    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#FazerDeposito(int, BigDecimal)
     */
    public String FazerDeposito(int idconta, BigDecimal valor) throws BankException {
    	String authcode = null;
    	
    	try {
    		Conta conta = contarepo.consultarporID(idconta);
    	
	    	if (conta==null) {
	    		throw new BankException("Conta " + idconta + " nao Existe");
	    	}
	    	
	    	if (conta.getTipoConta() == TipoConta.POUPANCA.getValue()) {
	    		
	    		conta.AtualizarDataAniversarioDeposito(valor);
	    		
	    	}
	    	
			Calendar c = Calendar.getInstance(); 
			
			Movimento movimento = new Movimento();
			
			AuthCodeGenerator gen = new AuthCodeGenerator();
			authcode = gen.GenerateAuthCode();
			
			movimento.setTsMovimento(new Timestamp(c.getTimeInMillis()));
			movimento.setVlrOperacao(valor);
			movimento.setAuthcode(authcode);
			movimento.setConta(conta);
			movimento.setFkOperacao(Operacao.DEPOSITO.getValue());
				
			contarepo.incluirMovimento(movimento);
			
	    	
	    	conta.depositar(valor);
	    	
	    	contarepo.atualizar(conta);
    	
    	} catch(Exception e) {
    	  throw new BankException(e.getMessage(),e);
    	}
    	
    	return authcode;
    		
    	
    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#VerificarSaldoDaConta(int)
     */
    public BigDecimal VerificarSaldoDaConta(int idconta) throws BankException {
    	
    	String result=null;
    	
    	try {
    	
	    	Conta conta = contarepo.consultarporID(idconta);
	    	
	    	if (conta==null) {
	    		throw new BankException("Conta " + idconta + " nao Existe");
	    	}
	    	
				return conta.getSaldo();
				
    	} catch(Exception e) {
      	  throw new BankException(e.getMessage(),e);
      	}
    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#VerificarExtratoContaCorrente(int, Date, Date)
     */
    public List<MovimentoDTO> VerificarExtratoContaCorrente(int idconta, Date inicio, Date fim) throws BankException {
    	List<Movimento> movimentos = new ArrayList<Movimento>();
    	List<MovimentoDTO> result = new ArrayList<MovimentoDTO>();
    	
    	try  {
    		movimentos = contarepo.movimentoPorPeriodo(inicio,fim);
    		
    	  	if (movimentos==null || movimentos.isEmpty()) {
        		throw new BankException("Nao Existem movimentos para o periodo informado");
        	}
        	
        	
        	Iterator<Movimento> imovimento = movimentos.iterator();    
        	
        	while(imovimento.hasNext()) {
        		result.add(imovimento.next().toDTO());
        		
        	}

    	} catch (Exception e) {
    		throw new BankException(e.getMessage(),e);
    	}
    	
    	
			return result;
    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#EfetuarSaque(int, BigDecimal)
     */
    public String EfetuarSaque(int idconta, BigDecimal valor) throws BankException {
 		Calendar c = Calendar.getInstance(); 
		String thecode=null;
    	
    	try {
    		Conta conta = contarepo.consultarporID(idconta);
    	
	    	if (conta==null) {
	    		throw new BankException("Conta " + idconta + " nao Existe");
	    	}
	    	
	    	if (conta.getTipoConta() == TipoConta.POUPANCA.getValue()) {
	    		
	    		conta.AtualizarDataAniversarioSaque(valor);
	    		
	    	}
	    	
	    	Movimento movimento = new Movimento();
	    	
			AuthCodeGenerator gen = new AuthCodeGenerator();
			thecode = gen.GenerateAuthCode();
			movimento.setTsMovimento(new Timestamp(c.getTimeInMillis()));
			movimento.setVlrOperacao(valor.negate());
			movimento.setAuthcode(thecode);
			movimento.setConta(conta);
			movimento.setFkOperacao(Operacao.SAQUE.getValue());
	    		    	
	    	conta.sacar(valor);
	    	contarepo.incluirMovimento(movimento);
	    	contarepo.atualizar(conta);
    	
    	} catch(Exception e) {
    	  throw new BankException(e.getMessage(),e);
    	}
    	
    	return thecode;

    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#TransferirFundos(int, int, BigDecimal)
     */
    public String[] TransferirFundos(int contadebitada, int contacreditada, BigDecimal valor) throws BankException {

    	String[] results = new String[2];
    	
    	try {
	    	Conta debitada = contarepo.consultarporID(contadebitada);
	    	
	    	Conta creditada = contarepo.consultarporID(contacreditada);
	    	
	    	if (debitada==null) {
	    		throw new BankException("Conta " + debitada + " nao Existe");
	    	}
	    	
	    	if (creditada==null) {
	    		throw new BankException("Conta " + creditada + " nao Existe");
	    	}
	    	
	    	results[0] = EfetuarSaque(contadebitada, valor);
	    	results[1] = FazerDeposito(contadebitada, valor);
	    	
    	} catch (Exception e) {
    		 throw new BankException(e.getMessage(),e);
    	}
    	
    	return results;
    }

	/**
     * @throws BankException 
	 * @see IServicoCliente#ListarContaPorCPF(String)
     */
    public List<ContaDTO> ListarContaPorCPF(String cpf) throws BankException {
    	ClienteDTO client = new ClienteDTO();
    	List<ContaDTO> result=new ArrayList<ContaDTO>();
    	try {  
	       	
        	Cliente entity = clienterepo.findByCPF(cpf);

        	if (entity==null) {
	    		throw new BankException("Cliente com o CPF : " + cpf + " nao Existe");
	    	}
        	
        	List<Conta> contas = contarepo.consultarPorCliente(entity);
        	       	
        	if (contas==null || contas.isEmpty()) {
	    		throw new BankException("Nao Existem contas para o cpf informado.");
	    	}
        	
        	
        	Iterator<Conta> iconta = contas.iterator();    
        	
        	while(iconta.hasNext()) {
        		result.add(iconta.next().toDTOLazy());
        		
        	}
        	
        	} catch (Exception e) {
        		throw new BankException(e.getMessage(),e);
        	}

    	return result;
    }
    
    /**
     * @throws BankException 
	 * @see IServicoBanco#ConsultarDadosConta(int)
     */
    public ContaDTO ConsultarDadosConta(int idconta) throws BankException {
    	
    	ContaDTO dto = new ContaDTO();
    	
    	try {
	    	Conta conta = contarepo.consultarporID(idconta);
	    	
	    	if (conta==null) {
	    		throw new BankException("Conta " + idconta + " nao Existe");
	    	}
	    	
	    	
	    	
	    	dto = conta.toDTO();
	    	
    	} catch (Exception e) {
    		throw new BankException(e.getMessage(),e);
    	}

			return dto;
    }

}
